{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/pietrolira/PPGEEC2318-Redes-Neurais-e-Deep-Learning/blob/main/Lista02/Q3.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "**3) Considere quatro distribuições gaussianas, $C_1, C_2, C_3, C_4$, em um espaço de entrada de dimensionalidade igual a oito, isto é $\\mathbf{x} = (x_1, x_2, \\ldots, x_8)^t$.**"
      ],
      "metadata": {
        "id": "YVND8XAz8UE1"
      }
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dY302cFtqvE3"
      },
      "source": [
        "**Visualização 2D com Autoencoder**\n",
        "\n",
        "Neste notebook, vamos:\n",
        "1. Gerar 4 distribuições gaussianas de 8 dimensões com médias distintas.\n",
        "2. Treinar uma rede **autoencoder** para reduzir essas 8 dimensões para 2.\n",
        "3. Visualizar os dados codificados em 2D."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Dxk4OSk6qvE7"
      },
      "source": [
        "**a) Todas as nuvens de dados formadas têm variâncias unitárias, mas centros ou vetores média são diferentes e dados por**\n",
        "$\\mathbf{m}_1 = (0,0,0,0,0,0,0,0)^t$,\n",
        "$\\mathbf{m}_2 = (4,0,0,0,0,0,0,0)^t$,\n",
        "$\\mathbf{m}_3 = (0,0,4,0,0,0,0,0)^t$,\n",
        "$\\mathbf{m}_4 = (0,0,0,0,0,0,0,4)^t$.\n",
        "\n",
        "**Resposta:**\n",
        "Cada uma das distribuições gaussianas tem variância unitária e diferentes médias dadas por:\n",
        "\n",
        "* $\\mathbf{m}_1 = (0, 0, 0, 0, 0, 0, 0, 0)^T$\n",
        "* $\\mathbf{m}_2 = (4, 0, 0, 0, 0, 0, 0, 0)^T$\n",
        "* $\\mathbf{m}_3 = (0, 0, 4, 0, 0, 0, 0, 0)^T$\n",
        "* $\\mathbf{m}_4 = (0, 0, 0, 0, 0, 0, 0, 4)^T$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TATrhXDVqvE8"
      },
      "source": [
        "**b) Utilizar uma rede de autoencoder para visualizar os dados em duas dimensões.**\n",
        "\n",
        "**Resposta:**\n",
        "Foi utilizada uma rede autoencoder para reduzir a dimensionalidade dos dados para duas dimensões (2d), ou seja, uma rede neural que aprenda a codificar os vetores de 8 dimensões em um espaço de 2 dimensões e consiga reconstruir os dados originais a partir disso."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b5JWgYAWqvFC"
      },
      "source": [
        "**c) O objetivo é visualizar os dados de dimensão 8 em um espaço de dimensão 2.**\n",
        "\n",
        "**Resposta:**\n",
        "O objetivo principal é visualizar os dados originalmente em 8 dimensões em um novo espaço bidimensional (2D), preservando suas estruturas e relações.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2Gnj_DWPqvFC"
      },
      "source": [
        "**d) Apresente os dados neste novo espaço.**\n",
        "\n",
        "**Resposta:**\n",
        "Os dados foram apresentados no novo espaço bidimensional, mostrando as quatro classes de forma visualmente separável, onde cada ponto representa um vetor codificado e cores distintas indicam cada uma das classes $C_1, C_2, C_3, C_4$."
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "---"
      ],
      "metadata": {
        "id": "VfGq4VNP80ku"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Código Python**"
      ],
      "metadata": {
        "id": "oA3Vh0rW86Ic"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.optim as optim\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "# **Fixar semente para reprodutibilidade**\n",
        "np.random.seed(42)\n",
        "torch.manual_seed(42)"
      ],
      "metadata": {
        "id": "9UcfvQnM99Bu"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Criar as quatro distribuições gaussianas**\n"
      ],
      "metadata": {
        "id": "KweUCQsj9DDN"
      }
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "T7gi3VN6qvFE"
      },
      "outputs": [],
      "source": [
        "means = [\n",
        "    np.array([0, 0, 0, 0, 0, 0, 0, 0]),\n",
        "    np.array([4, 0, 0, 0, 0, 0, 0, 0]),\n",
        "    np.array([0, 0, 4, 0, 0, 0, 0, 0]),\n",
        "    np.array([0, 0, 0, 0, 0, 0, 0, 4])\n",
        "]\n",
        "\n",
        "num_samples_per_class = 500\n",
        "X, y = [], []\n",
        "\n",
        "# Gerar amostras com variância unitária\n",
        "for i, mean in enumerate(means):\n",
        "    cov = np.eye(8)\n",
        "    samples = np.random.multivariate_normal(mean, cov, num_samples_per_class)\n",
        "    X.append(samples)\n",
        "    y.append(np.full(num_samples_per_class, i))\n",
        "\n",
        "X = np.vstack(X)\n",
        "y = np.concatenate(y)\n",
        "\n",
        "# Converter para tensores\n",
        "\n",
        "X_tensor = torch.tensor(X, dtype=torch.float32)"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Definir Autoencoder**"
      ],
      "metadata": {
        "id": "2eq5CXGS9NEj"
      }
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pALbYUkxqvFE"
      },
      "outputs": [],
      "source": [
        "class Autoencoder(nn.Module):\n",
        "    def __init__(self):\n",
        "        super(Autoencoder, self).__init__()\n",
        "        self.encoder = nn.Sequential(\n",
        "            nn.Linear(8, 4),\n",
        "            nn.ReLU(),\n",
        "            nn.Linear(4, 2)\n",
        "        )\n",
        "        self.decoder = nn.Sequential(\n",
        "            nn.Linear(2, 4),\n",
        "            nn.ReLU(),\n",
        "            nn.Linear(4, 8)\n",
        "        )\n",
        "\n",
        "    def forward(self, x):\n",
        "        z = self.encoder(x)\n",
        "        x_recon = self.decoder(z)\n",
        "        return x_recon\n",
        "\n",
        "# Instanciar modelo\n",
        "model = Autoencoder()\n",
        "criterion = nn.MSELoss()\n",
        "optimizer = optim.Adam(model.parameters(), lr=1e-3)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NotVo44HqvFE"
      },
      "outputs": [],
      "source": [
        "# Treinamento\n",
        "epochs = 200\n",
        "for epoch in range(epochs):\n",
        "    optimizer.zero_grad()\n",
        "    outputs = model(X_tensor)\n",
        "    loss = criterion(outputs, X_tensor)\n",
        "    loss.backward()\n",
        "    optimizer.step()\n",
        "\n",
        "    if (epoch + 1) % 20 == 0:\n",
        "        print(f\"Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Obter representações em 2D**\n"
      ],
      "metadata": {
        "id": "531vyEhB9X3t"
      }
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Wcma5SNrqvFF"
      },
      "outputs": [],
      "source": [
        "with torch.no_grad():\n",
        "    encoded = model.encoder(X_tensor).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Visualizar**\n"
      ],
      "metadata": {
        "id": "9iDM5N_U9ZdT"
      }
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vN7Frca0qvFF"
      },
      "outputs": [],
      "source": [
        "plt.figure(figsize=(8, 6))\n",
        "colors = ['red', 'green', 'blue', 'orange']\n",
        "labels = ['C1', 'C2', 'C3', 'C4']\n",
        "\n",
        "for i in range(4):\n",
        "    plt.scatter(encoded[y == i, 0], encoded[y == i, 1],\n",
        "                label=labels[i], alpha=0.6, color=colors[i])\n",
        "\n",
        "plt.title('Visualização 2D com Autoencoder')\n",
        "plt.xlabel('Dimensão 1')\n",
        "plt.ylabel('Dimensão 2')\n",
        "plt.legend()\n",
        "plt.grid(True)\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.x"
    },
    "colab": {
      "provenance": [],
      "include_colab_link": true
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}